#include "Texture.h"
#include "TGA.h"
#include <string.h>

char *GetSideCubeData(char *bufferTGA, int x, int y, int width, int height, int bpp);

Texture::Texture(void)
{
	m_textureID = 0;
	m_target = 0;
}

Texture::~Texture(void)
{
	if (m_textureID)
	{
		glDeleteTextures(1, &m_textureID);
	}
}

void Texture::Init(const char *fileName, GLenum target, int tiling, const char* id)
{
	strcpy(m_id, id);
	m_target = target;

	// create the OpenGL ES texture resource and get the handle
	glGenTextures(1, &m_textureID);
	 
	// bind the texture to the 2D texture type
	glBindTexture(m_target, m_textureID);
	 
	// create CPU buffer and load it with the image data
	int width, height, bpp;
	char * bufferTGA = LoadTGA(fileName, &width, &height, &bpp);
	 
	// load the image data into OpenGL ES texture resource
	int format;
	if(bpp == 24)
	{
		format = GL_RGB;
	}

	else
	{
		format = GL_RGBA;
	}

	if (m_target == GL_TEXTURE_2D)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, bufferTGA);
	}

	else if (m_target == GL_TEXTURE_CUBE_MAP)
	{
		char *side[6];
		int w = width/4;
		int h = height/3;

		side[0] = GetSideCubeData(bufferTGA, w*2, h*1, w, h, bpp);
		side[1] = GetSideCubeData(bufferTGA, w*0, h*1, w, h, bpp);
		side[2] = GetSideCubeData(bufferTGA, w*1, h*2, w, h, bpp);
		side[3] = GetSideCubeData(bufferTGA, w*1, h*0, w, h, bpp);
		side[4] = GetSideCubeData(bufferTGA, w*1, h*1, w, h, bpp);
		side[5] = GetSideCubeData(bufferTGA, w*3, h*1, w, h, bpp);

		for (int i = 0; i < 6; i++)
		{
			glTexImage2D ( 
			   GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,
			   0,
			   format,
			   w,
			   h,
			   0,
			   format,
			   GL_UNSIGNED_BYTE,
			   side[i]);
		}

		//free the client memory
		for (int i = 0; i < 6; i++)
		{
			delete side[i];
		}
	}

	// free the client memory
	delete [] bufferTGA;

	// generate the mipmap chain
	glGenerateMipmap(m_target);

	//set the filters for minification and magnification
	glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	
	glTexParameteri(m_target, GL_TEXTURE_WRAP_S, tiling);
	glTexParameteri(m_target, GL_TEXTURE_WRAP_T, tiling);

	glBindTexture(m_target, 0);
}

GLuint Texture::GetTextureID()
{
	return m_textureID;
}

GLenum Texture::GetTarget()
{
	return m_target;
}

char *GetSideCubeData(char *bufferTGA, int x, int y, int width, int height, int bpp)
{
	int k = 0;
	char *side = new char[width * height * bpp/8];
	for (int i = y + height - 1; i >= y; i--)
	{
		for (int j = x * bpp/8; j < (x + width) * bpp/8; j++)
		{
			side[k++] = bufferTGA[i * width * 4 * bpp/8 + j];
		}
	}
	return side;
}

const char* Texture::GetID()
{
	return m_id;
}

void Texture::SetTextureID(GLuint textureID)
{
	m_textureID = textureID;
}
void Texture::SetTarget(GLuint target)
{
	m_target = target;
}